//
// TypeList.h
//
// Library: Foundation
// Package: Core
// Module:  TypeList
//
// Implementation of the TypeList template.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Portions extracted and adapted from
// The Loki Library
// Copyright (c) 2001 by Andrei Alexandrescu
//
// SPDX-License-Identifier:	BSL-1.0
//


#ifndef Foundation_TypeList_INCLUDED
#define Foundation_TypeList_INCLUDED


#include "Poco/Foundation.h"
#include "Poco/MetaProgramming.h"


namespace Poco
{


template <class Head, class Tail>
struct TypeList;


struct NullTypeList
{
    enum
    {
        length = 0
    };

    bool operator==(const NullTypeList &) const { return true; }

    bool operator!=(const NullTypeList &) const { return false; }

    bool operator<(const NullTypeList &) const { return false; }
};


template <class Head, class Tail>
struct TypeList
/// Compile Time List of Types
{
    typedef Head HeadType;
    typedef Tail TailType;
    typedef typename TypeWrapper<HeadType>::CONSTTYPE ConstHeadType;
    typedef typename TypeWrapper<TailType>::CONSTTYPE ConstTailType;
    enum
    {
        length = TailType::length + 1
    };

    TypeList() : head(), tail() { }

    TypeList(ConstHeadType & h, ConstTailType & t) : head(h), tail(t) { }

    TypeList(const TypeList & tl) : head(tl.head), tail(tl.tail) { }

    TypeList & operator=(const TypeList & tl)
    {
        if (this != &tl)
        {
            head = tl.head;
            tail = tl.tail;
        }
        return *this;
    }

    bool operator==(const TypeList & tl) const { return tl.head == head && tl.tail == tail; }

    bool operator!=(const TypeList & tl) const { return !(*this == tl); }

    bool operator<(const TypeList & tl) const
    {
        if (head < tl.head)
            return true;
        else if (head == tl.head)
            return tail < tl.tail;
        return false;
    }

    HeadType head;
    TailType tail;
};


template <
    typename T0 = NullTypeList,
    typename T1 = NullTypeList,
    typename T2 = NullTypeList,
    typename T3 = NullTypeList,
    typename T4 = NullTypeList,
    typename T5 = NullTypeList,
    typename T6 = NullTypeList,
    typename T7 = NullTypeList,
    typename T8 = NullTypeList,
    typename T9 = NullTypeList,
    typename T10 = NullTypeList,
    typename T11 = NullTypeList,
    typename T12 = NullTypeList,
    typename T13 = NullTypeList,
    typename T14 = NullTypeList,
    typename T15 = NullTypeList,
    typename T16 = NullTypeList,
    typename T17 = NullTypeList,
    typename T18 = NullTypeList,
    typename T19 = NullTypeList,
    typename T20 = NullTypeList,
    typename T21 = NullTypeList,
    typename T22 = NullTypeList,
    typename T23 = NullTypeList,
    typename T24 = NullTypeList,
    typename T25 = NullTypeList,
    typename T26 = NullTypeList,
    typename T27 = NullTypeList,
    typename T28 = NullTypeList,
    typename T29 = NullTypeList,
    typename T30 = NullTypeList,
    typename T31 = NullTypeList,
    typename T32 = NullTypeList,
    typename T33 = NullTypeList,
    typename T34 = NullTypeList,
    typename T35 = NullTypeList,
    typename T36 = NullTypeList,
    typename T37 = NullTypeList,
    typename T38 = NullTypeList,
    typename T39 = NullTypeList>
struct TypeListType
/// TypeListType takes 1 - 40 typename arguments.
/// Usage:
///
/// TypeListType<T0, T1, ... , Tn>::HeadType typeList;
///
/// typeList is a TypeList of T0, T1, ... , Tn
{
private:
    typedef typename TypeListType<
        T1,
        T2,
        T3,
        T4,
        T5,
        T6,
        T7,
        T8,
        T9,
        T10,
        T11,
        T12,
        T13,
        T14,
        T15,
        T16,
        T17,
        T18,
        T19,
        T20,
        T21,
        T22,
        T23,
        T24,
        T25,
        T26,
        T27,
        T28,
        T29,
        T30,
        T31,
        T32,
        T33,
        T34,
        T35,
        T36,
        T37,
        T38,
        T39>::HeadType TailType;

public:
    typedef TypeList<T0, TailType> HeadType;
};


template <>
struct TypeListType<>
{
    typedef NullTypeList HeadType;
};


template <int n>
struct Getter
{
    template <class Ret, class Head, class Tail>
    inline static Ret & get(TypeList<Head, Tail> & val)
    {
        return Getter<n - 1>::template get<Ret, typename Tail::HeadType, typename Tail::TailType>(val.tail);
    }

    template <class Ret, class Head, class Tail>
    inline static const Ret & get(const TypeList<Head, Tail> & val)
    {
        return Getter<n - 1>::template get<Ret, typename Tail::HeadType, typename Tail::TailType>(val.tail);
    }
};


template <>
struct Getter<0>
{
    template <class Ret, class Head, class Tail>
    inline static Ret & get(TypeList<Head, Tail> & val)
    {
        return val.head;
    }

    template <class Ret, class Head, class Tail>
    inline static const Ret & get(const TypeList<Head, Tail> & val)
    {
        return val.head;
    }
};


template <int N, class Head>
struct TypeGetter;


template <int N, class Head, class Tail>
struct TypeGetter<N, TypeList<Head, Tail>>
{
    typedef typename TypeGetter<N - 1, Tail>::HeadType HeadType;
    typedef typename TypeWrapper<HeadType>::CONSTTYPE ConstHeadType;
};


template <class Head, class Tail>
struct TypeGetter<0, TypeList<Head, Tail>>
{
    typedef typename TypeList<Head, Tail>::HeadType HeadType;
    typedef typename TypeWrapper<HeadType>::CONSTTYPE ConstHeadType;
};


template <class Head, class T>
struct TypeLocator;
/// TypeLocator returns the first occurrence of the type T in Head
/// or -1 if the type is not found.
///
/// Usage example:
///
/// TypeLocator<Head, int>::HeadType TypeLoc;
///
/// if (2 == TypeLoc.value) ...
///


template <class T>
struct TypeLocator<NullTypeList, T>
{
    enum
    {
        value = -1
    };
};


template <class T, class Tail>
struct TypeLocator<TypeList<T, Tail>, T>
{
    enum
    {
        value = 0
    };
};


template <class Head, class Tail, class T>
struct TypeLocator<TypeList<Head, Tail>, T>
{
private:
    enum
    {
        tmp = TypeLocator<Tail, T>::value
    };

public:
    enum
    {
        value = tmp == -1 ? -1 : 1 + tmp
    };
};


template <class Head, class T>
struct TypeAppender;
/// TypeAppender appends T (type or a TypeList) to Head.
///
/// Usage:
///
/// typedef TypeListType<char>::HeadType Type1;
/// typedef TypeAppender<Type1, int>::HeadType Type2;
/// (Type2 is a TypeList of char,int)
///
///	typedef TypeListType<float, double>::HeadType Type3;
/// typedef TypeAppender<Type2, Type3>::HeadType Type4;
/// (Type4 is a TypeList of char,int,float,double)
///


template <>
struct TypeAppender<NullTypeList, NullTypeList>
{
    typedef NullTypeList HeadType;
};


template <class T>
struct TypeAppender<NullTypeList, T>
{
    typedef TypeList<T, NullTypeList> HeadType;
};


template <class Head, class Tail>
struct TypeAppender<NullTypeList, TypeList<Head, Tail>>
{
    typedef TypeList<Head, Tail> HeadType;
};


template <class Head, class Tail, class T>
struct TypeAppender<TypeList<Head, Tail>, T>
{
    typedef TypeList<Head, typename TypeAppender<Tail, T>::HeadType> HeadType;
};


template <class Head, class T>
struct TypeOneEraser;
/// TypeOneEraser erases the first occurrence of the type T in Head.
/// Usage:
///
/// typedef TypeListType<char, int, float>::HeadType Type3;
/// typedef TypeOneEraser<Type3, int>::HeadType Type2;
/// (Type2 is a TypeList of char,float)
///


template <class T>
struct TypeOneEraser<NullTypeList, T>
{
    typedef NullTypeList HeadType;
};


template <class T, class Tail>
struct TypeOneEraser<TypeList<T, Tail>, T>
{
    typedef Tail HeadType;
};


template <class Head, class Tail, class T>
struct TypeOneEraser<TypeList<Head, Tail>, T>
{
    typedef TypeList<Head, typename TypeOneEraser<Tail, T>::HeadType> HeadType;
};


template <class Head, class T>
struct TypeAllEraser;
/// TypeAllEraser erases all the occurrence of the type T in Head.
/// Usage:
///
/// typedef TypeListType<char, int, float, int>::HeadType Type4;
/// typedef TypeAllEraser<Type4, int>::HeadType Type2;
/// (Type2 is a TypeList of char,float)
///


template <class T>
struct TypeAllEraser<NullTypeList, T>
{
    typedef NullTypeList HeadType;
};


template <class T, class Tail>
struct TypeAllEraser<TypeList<T, Tail>, T>
{
    typedef typename TypeAllEraser<Tail, T>::HeadType HeadType;
};


template <class Head, class Tail, class T>
struct TypeAllEraser<TypeList<Head, Tail>, T>
{
    typedef TypeList<Head, typename TypeAllEraser<Tail, T>::HeadType> HeadType;
};


template <class Head>
struct TypeDuplicateEraser;
/// TypeDuplicateEraser erases all but the first occurrence of the type T in Head.
/// Usage:
///
/// typedef TypeListType<char, int, float, int>::HeadType Type4;
/// typedef TypeDuplicateEraser<Type4, int>::HeadType Type3;
/// (Type3 is a TypeList of char,int,float)
///


template <>
struct TypeDuplicateEraser<NullTypeList>
{
    typedef NullTypeList HeadType;
};


template <class Head, class Tail>
struct TypeDuplicateEraser<TypeList<Head, Tail>>
{
private:
    typedef typename TypeDuplicateEraser<Tail>::HeadType L1;
    typedef typename TypeOneEraser<L1, Head>::HeadType L2;

public:
    typedef TypeList<Head, L2> HeadType;
};


template <class Head, class T, class R>
struct TypeOneReplacer;
/// TypeOneReplacer replaces the first occurrence
/// of the type T in Head with type R.
/// Usage:
///
/// typedef TypeListType<char, int, float, int>::HeadType Type4;
/// typedef TypeOneReplacer<Type4, int, double>::HeadType TypeR;
/// (TypeR is a TypeList of char,double,float,int)
///


template <class T, class R>
struct TypeOneReplacer<NullTypeList, T, R>
{
    typedef NullTypeList HeadType;
};


template <class T, class Tail, class R>
struct TypeOneReplacer<TypeList<T, Tail>, T, R>
{
    typedef TypeList<R, Tail> HeadType;
};


template <class Head, class Tail, class T, class R>
struct TypeOneReplacer<TypeList<Head, Tail>, T, R>
{
    typedef TypeList<Head, typename TypeOneReplacer<Tail, T, R>::HeadType> HeadType;
};


template <class Head, class T, class R>
struct TypeAllReplacer;
/// TypeAllReplacer replaces all the occurrence
/// of the type T in Head with type R.
/// Usage:
///
/// typedef TypeListType<char, int, float, int>::HeadType Type4;
/// typedef TypeAllReplacer<Type4, int, double>::HeadType TypeR;
/// (TypeR is a TypeList of char,double,float,double)
///


template <class T, class R>
struct TypeAllReplacer<NullTypeList, T, R>
{
    typedef NullTypeList HeadType;
};


template <class T, class Tail, class R>
struct TypeAllReplacer<TypeList<T, Tail>, T, R>
{
    typedef TypeList<R, typename TypeAllReplacer<Tail, T, R>::HeadType> HeadType;
};


template <class Head, class Tail, class T, class R>
struct TypeAllReplacer<TypeList<Head, Tail>, T, R>
{
    typedef TypeList<Head, typename TypeAllReplacer<Tail, T, R>::HeadType> HeadType;
};


} // namespace Poco


#endif // Foundation_TypeList_INCLUDED
